import re

__author__ = 'YeeHin Kwok'



""" MicroCompiler 

<program>       ::=     program <id>; declare    declareList;    { StmtList}
<declareList>    ::=    varDeclare {, varDeclare};
<varDeclare> ::=    idsym    [ = number | "[" number "]" 

<stmt> ::=  variable( = expression | parameter) | <printStmt> ::= print "("<print_item>{,<print_item>}")"| if <condition> <stmt> [else <stmt>]|
            <readStmt> ::= read "("variable")"  |  <id> = <expression> | 
             while <condition> <stmt>| <stmtList>  | do <stmsList> forever | break | continue

<stmtlist>      ::=     <stmt> { ; <stmt> }
<print_item>    ::=    expression | string

<condition>    ::=    [not] <conditionalexp>
<conditionalexp>    ::=    <expression>[<relational_op>    <expression>]      
<relational_op>    ::=    <|<=|==|!=|>|>=

<expression> ::=  <term> {  (+ | -)  <term> }      
<term>    ::=    <factor> {(*|/) <factor>}
<factor> ::= [+|-] <id> | <number> | "("<expression>")"

<variable>    ::=    <id> [<arraySub>]
<arraySub>    ::=    "["<expression>"]"

<constnat>    ::=    <number>
<id>        ::=    A-Z{A-Z _ 0-9 ? }
"""

import sys
import shlex

#===============================================================================
# # Lexical Analyser - the "Scanner" - Define the TokenTypes
#===============================================================================

tokenNames = \
  [ "unknownToken", "idsym", "assignsym", "leftbrace", "rightbrace",
    "varDeclareym", "semicolon", "whilesym", "leftbracket", "rightbracket",
    "printsym", "ifsym", "equals", "lessthan", "greaterthan",
    "number", "plus", "minus", "mpy", "div", "elsesym", "declaresym", "forsym", "andsym", "elifsym", "dosym", "returnsym", "notsym",
    "continuesym", "breaksym", "nonesym", "programsym", "functionsym", "leftsquarebracket", "rightsquarebracket",
    "lessthanequal", "colon", "comma", "comment", "commentstr", "dot", " greaterthanequal", "jumpeq", "jumpne",
    "andop", "orop", "quote ", "stringsym", "arraySubsym", "readsym", "endfile"]

# define the tokens as variables
unknownToken, idsym, assignsym, leftbrace, rightbrace, \
    varDeclareym, semicolon, whilesym, leftbracket, rightbracket, \
    printsym, ifsym, equals, lessthan, greaterthan, \
    number, plus, minus, mpy, div, elsesym, declaresym, forsym, andsym, elifsym, dosym, returnsym, notsym, \
    continuesym, breaksym, nonesym, programsym, functionsym, leftsquarebracket, rightsquarebracket, \
    lessthanequal, colon, comma, comment, commentstr, dot, greaterthanequal, jumpeq, jumpne, \
    andop, orop, quote, stringsym, arraySubsym, readsym, endfile = range(0, len(tokenNames))

#===============================================================================
class symbol:
#===============================================================================
    name = None  # String representation
    token = None;  # Corresponding token
    address = 0;  # For variables, their runtime address
    value = None  # on defined for numbers
    

    def __init__(self, name, token, value=0):
        self.name = name
        self.token = token
        self.address = 0  # for identifiers, their address
        self.value = value  # for numbers, their value


symtbl = {};  # The Symbol Table, a dictionary of symbols indexed by name

#======================================================================
# GLOBALS for output of Lexical Analyser
# Set by each call to GeToken()

token = None;  # A symbol
line = "\n"  # the complex source file as a string
charIndex = 0  # the position in the source

linenumber = 0  # The current  number

tokennum = 0

whichidentifier = None;

arraySubaddress = 0;
endaddress = 0;

i = 700
j = 700 
counterafter = i
counterafter1 = j


EOF = chr(0)
#======================================================================
# Run Time Code Generation Variables

varptr = 500  # Arbitrary base address of memory for variables
codeptr = 10  # Address to output next instruction (for code)


#===============================================================================
#                    Symbol Table Management Routines
#===============================================================================

#===============================================================================
def addToSymTbl (name, token):
#===============================================================================
    symtbl[name] = symbol(name, token)  # Add a new symbol to the dictionary
    return symtbl[name]


#===============================================================================
def lookup (thisName):
#===============================================================================
    "# Find a given identifier in the Symbol Table, Return the symtbl entry"
    if symtbl.has_key(thisName):  # thisName has been seen before
        return symtbl[thisName]  # return the symtbl entry
    else: return None


#===============================================================================
def initSymTbl():
#===============================================================================
    "# Initialise Symbol Table, and preload reserved words"
    addToSymTbl('var', varDeclareym)  # VAR
    addToSymTbl('program', programsym)
    addToSymTbl('function', functionsym)
    addToSymTbl('while', whilesym)  # WHILE
    addToSymTbl('print', printsym)  # PRINT
    addToSymTbl('else', elsesym)
    addToSymTbl('elif', elifsym)
    addToSymTbl('if', ifsym)
    addToSymTbl('declare', declaresym)
    addToSymTbl('for', forsym)
    addToSymTbl('None', nonesym)
    addToSymTbl('continue', continuesym)
    addToSymTbl('read', readsym)  # READINT
    addToSymTbl('do', dosym)
    addToSymTbl('return', returnsym)
    addToSymTbl('not', notsym)

    # Now add symbols - NB only single character symbols are here
    #                      multicharacter one like ">=" are still to do
    addToSymTbl('=', assignsym)
    addToSymTbl('#', comment)
    addToSymTbl('<', lessthan)
    addToSymTbl('>', greaterthan)
    addToSymTbl('{', leftbrace)
    addToSymTbl('}', rightbrace)
    addToSymTbl('(', leftbracket)
    addToSymTbl(')', rightbracket)
    addToSymTbl('+', plus)
    addToSymTbl('-', minus)
    addToSymTbl(';', semicolon)
    addToSymTbl('break', breaksym)
    addToSymTbl('*', mpy)
    addToSymTbl('/', div)
    addToSymTbl('[', leftsquarebracket)
    addToSymTbl(']', rightsquarebracket)
    addToSymTbl(':', colon)
    addToSymTbl(',', comma)
    addToSymTbl('.', dot)
    addToSymTbl('==', jumpeq)
    addToSymTbl('!=', jumpne)
    addToSymTbl('&&', andop)
    addToSymTbl('||', orop)
    addToSymTbl('"', quote)
    addToSymTbl(EOF, endfile)


#===============================================================================
#                       Scanner Diagnostics
#===============================================================================
def printToken(tok):
#===============================================================================
    " - display the specified token."
    if tok.token == idsym:
       print "Token = %10s,  %-10s  adr = %3d, val = %d" % \
             (tokenNames[tok.token], tok.name, tok.address, tok.value)
    elif tok.token == number:
       print "Token = %10s  %d" % (tokenNames[tok.token], tok.value)
    else:
       print "Token = %10s" % tokenNames[tok.token]

#==============================?=================================================
def dumpSymTbl():
#===============================================================================
    """ Dump all the tokens in the symboltable """
    print("# *** Symbol Table ***")
    for name in symtbl.keys():  # keys is a list of the names (printable form of tokens)
        tok = symtbl[name]
        if tok.token == idsym:
            print("#"),
            printToken(tok)

#===============================================================================
def getch():
#===============================================================================
    global line
    global charIndex
    global linenumber

    while True:
        if charIndex < len(line):  # See if used up current line
            ch = line[charIndex]  # if not, get character
            charIndex = charIndex + 1  # & move pointer for next time
        else:
            
            # line = f.readline()
            # if  line == "": line = EOF
            dumpSymTbl()
            print "#End of File"
            print "#--> ",
            line = raw_input() + "\n"  # read new line, adding \n so it's like f.readline()
#            line = srcfile.read()
            charIndex = 0  # & reset character pointer
            linenumber = linenumber + 1
            continue

        if ch == "\n":
            ch = " "

        if ch == '?':
            dumpSymTbl()
            continue
        return ch

#===============================================================================
def ungetch():
#===============================================================================
    """ Unget the next character peeked at when building variables, numbers
        and when distinguishing between >= and > ...
    """
    global charIndex;
    charIndex = charIndex - 1;

#===============================================================================
def getoken():
#===============================================================================
    """ GETOKEN - Put next token into the global TOKEN """
    global token
    global i
    global m
    global counterafter
    global counterafter1
    x = 0
    ch = getch()  # skip whitespace
    while ch in ["\t", " ", "\n"]:
        ch = getch()

    # If ch is alphabetic then this is start of reserved word or an identifier
    if ch.isalpha():  # Letter therefore it's either identifier or reserved word
        name = ""
        while ch.isalpha() or ch.isdigit() or ch == "_":
            name = name + ch
            ch = getch()

        ungetch()  # let terminator be used next time

        token = lookup(name)  # See if token's known
        if token is None:  # if not
            token = addToSymTbl(name, idsym)  #   add as 'idsym'-IDENTIFIER

        return  # we've set token.token to either id or tokentype of reserved word

    elif ch in ["{", "}", "(", ")", "[", "]", "+", "-", "*", "/", ";", ",", ":", EOF]:
        token = lookup(ch)  # preloaded with appropriate token

    elif ch.isdigit():
        # In the real version, build number and don't forget to end with ungetch()
        while(ch.isdigit() == True):
            x = str(x) + str(ch)
            ch = getch()
        ch = ungetch()

        token = symbol(x, number, value=int(x))  # simplistic SINGLE DIGIT Ascii to Binary
        return
    
    # If ch is #
    elif ch == '#':
        str1 = ""
        ch = getch()
        #End while if the comment have ""
        while ch != " ":
            str1 = str(str1) + str(ch)

            ch = getch()

        ch = getch()
        print("#comment: " + str(str1))

        return
    
    # If ch is "
    elif ch == '"':
        a = ""
        ch = getch()
        counterafter1 = counterafter
                    
        i = counterafter
        if counterafter != 700:
            counterafter = counterafter + 4;
            counterafter = i
            
        
        while (ch != '"'):
            
            a = str(a) + str(ch)
            if ch != " ":
                b = "'" + ch + "'"
                emit(i, "constant", b)
                ch = getch()
            else:
                ch = getch()
            i = i + 1 
        emit(i, "constant", 13)
        emit(i + 1, "constant", 0)
        emit(i + 2, "return", '')
        ch = getch()
        counterafter = i + 3

        token = symbol(a, stringsym, value=str(a))  # simplistic SINGLE DIGIT Ascii to Binary

        return
    
    # If ch is <
    elif ch == "<":
        ch = getch()
        if ch == "=":
            lt = ""
            lt = "<" + "="

            token = symbol(lt, lessthanequal, value=str(lt))  # simplistic SINGLE DIGIT Ascii to Binary
            return
        else:
            ch == ungetch()
            token = symbol("<", lessthan, value="<")  # simplistic SINGLE DIGIT Ascii to Binary
            return
    
    # If ch is !    
    elif ch == "!":
        ne = ""
        ch = getch()
        if ch == "=":
            ne = "!" + "="

            token = symbol(ne, jumpne, value=str(ne))  # simplistic SINGLE DIGIT Ascii to Binary
            return
        else:
            ch == ungetch()
            token = symbol("!", NOT , value="!")  # simplistic SINGLE DIGIT Ascii to Binary
            return
    
    # If ch is =
    elif ch == "=":
        eq = ""
        ch = getch()
        if ch == "=":
            
            eq = "=" + "="

            token = symbol(eq, jumpeq, value=str(eq))  # simplistic SINGLE DIGIT Ascii to Binary
            return
        else:
            ch == ungetch()
            token = symbol("=", assignsym, value="=")  # simplistic SINGLE DIGIT Ascii to Binary
            return
        
    # If ch is >    
    elif ch == ">":
        gt = ""
        ch = getch()
        if ch == "=":
            gt = ">" + "="

            token = symbol(gt, greaterthanequal, value=str(gt))  # simplistic SINGLE DIGIT Ascii to Binary
            return
        else:
            ch == ungetch()
            token = symbol(">", greaterthan, value=">")  # simplistic SINGLE DIGIT Ascii to Binary
            return
        
    else:
        print "Unknown character -->%s<- decimal %d" % (ch, ord(ch))
        sys.exit(1)  # Abort Compilation

#======================================================================
# THE GRAMMAR

# <program>       ::=     program <id>; declare    declareList;    { StmtList}
# <declareList>    ::=    varDeclare {, varDeclare};
# <varDeclare> ::=    idsym    [ = number | "[" number "]" 

# <stmt> ::=  variable( = expression | parameter) | <printStmt> ::= print "("<print_item>{,<print_item>}")"| if <condition> <stmt> [else <stmt>]|
#            <readStmt> ::= read "("variable")"  |  <id> = <expression> | 
#             while <condition> <stmt>| <stmtList>  | do <stmsList> forever | break | continue

# <stmtlist>      ::=     <stmt> { ; <stmt> }
# <print_item>    ::=    expression | string

# <condition>    ::=    [not] <conditionalexp>
# <conditionalexp>    ::=    <expression>[<relational_op>    <expression>]      
# <relational_op>    ::=    <|<=|==|!=|>|>=

# <expression> ::=  <term> {  (+ | -)  <term> }      
# <term>    ::=    <factor> {(*|/) <factor>}
# <factor> ::= [+|-] <id> | <number> | "("<expression>")"

# <variable>    ::=    <id> [<arraySub>]
# <arraySub>    ::=    "["<expression>"]"

#======================================================================
#                  Centralised Parser Error Message handler
#======================================================================


#===============================================================================
def error (msg):
#===============================================================================
    print line
    print "-" * charIndex, "^"
    print("Error on  %d - %s\n" % (number, msg))
    printToken(token)
    print("\n")

#===============================================================================
def emit (memadr, opcode, parameter):
#===============================================================================
    """EMIT CODE - Emit a  of code with a Parameter
    if first arg is zero - (the memory address), use and incr CODEPTR"""
    global codeptr

    if (memadr == 0):
        memadr = codeptr
        codeptr = codeptr + 1
    print "%6d  %-8s %-7s" % (memadr, opcode, parameter)

#===============================================================================
def declareList() :
#    declareList    ::=    varDeclare {, varDeclare};
#===============================================================================
    varDeclare()
     
    while token.token != semicolon : 
        
        if token.token == comma:
            varDeclare()
    getoken()

#===============================================================================
def varDeclare() :
# <varDeclare> ::=    idsym    [ = number | "[" number "]" 
#===============================================================================

    ta = 0
    tn = []
    global varptr;
    global whichidaddress;
    global arraySubaddress;

    getoken();

    if token.token == idsym:
        ta = token.address
        tn = token.name
        getoken()

        if token.token == leftsquarebracket:

            getoken()
            if token.token == number:  # number
                
                symtbl[tn].address = varptr;
                while (token.value != 0):
                    varptr = varptr + 1
                    token.value = token.value - 1
          
                
                getoken()
                
                if token.token == rightsquarebracket:
                    getoken()
                else:
                    error("Expected rightsquarebracket at the end of arraySub declare")
                
        else:
            if ta != 0:
                print("#"),
                print("%c already declared\n", tn);
                # assignStmt()
            else:
                symtbl[tn].address = varptr;
                varptr = varptr + 1;
#                emit(0, "load", varptr)

#===============================================================================
def variable():
#    <variable>    ::=    <id> [<arraySub>]
#===============================================================================    
    
    if token.token == idsym:
        expression()
 #       getoken()
        
        if token.token == leftsquarebracket:
            arraySub()

#===============================================================================
def arraySub():
#    <arraySub>    ::=    "["<expression>"]"
#===============================================================================
    global arraySub;

    expression()
    
    if token.token == rightsquarebracket:
        getoken()
    else:
        error("Expected rightsquarebracket for array expression")

#===============================================================================
def parameters():
#===============================================================================
    varDeclare()
    
    if token.token == comma:
        varDeclare()
    
#    getoken()
#======================================================================
# STMTLIST
# <stmtlist>  ::= <stmt> { ; <stmt> }

#===============================================================================
def stmtList():
#===============================================================================
    stmt()

    while (token.token != rightbrace):
        stmt()

#======================================================================
# STMT
# <stmt> ::=  variable( = expression | parameter) | <printStmt> ::= print "("<print_item>{,<print_item>}")"| if <condition> <stmt> [else <stmt>]|
#            <readStmt> ::= read "("variable")"  |  <id> = <expression> | 
#             while <condition> <stmt>| <stmtList>  | do <stmsList> forever | break | continue
#===============================================================================
def stmt():
#===============================================================================
    global codeptr

    thisStmtAdr = codeptr  # Jump DEMO - not part of Stmt

    if token.token == variable:
        getoken()
        if token.token == assignsym:
            expression()
        else:
            parameter()
        
    elif token.token == ifsym:
        ifStmt()
                    
    elif token.token == whilesym:
        whileStmt() 
        
    elif token.token == stmtList:
        stmtList()
        
    elif  token.token == printsym:
        printStmt()

    elif token.token == readsym:
        readStmt()
    
    elif token.token == declaresym:
        declareList()
        
    elif token.token == dosym:
        doStmt()
    
    elif token.token == breaksym:
        emit(0, "halt", '')
        getoken()
            
    elif token.token == continuesym:
        continueStmt()
                
    elif token.token == number:
        expression()
        
    elif token.token == idsym:
        assignStmt()
    
    elif token.token == functionsym:
        function()

    elif token.token == returnsym:
        returnStmt()
    else:
        error("Expected start of a statement")
    
    if  token.token == semicolon or token.token == comma:
        getoken()
    

    

#===============================================================================
def printStmt():
#    <printStmt> ::= print "("<print_item>{,<print_item>}")"
#===============================================================================
    
    getoken()  # skip "print"
    
    if token.token == leftbracket:
        getoken()
    else:
        error("Expected leftbracket before the print-item")
    
    print_item()
    
    if token.token == comma:
        print_item()
    
    getoken()
    
    if token.token == rightbracket:
        getoken()
                      
    if token.token == semicolon:
        getoken()
    
#===============================================================================        
def print_item():
#    <print_item>    ::=    expression | string
#===============================================================================
    #    expression
    if token.token == idsym:
        expression()
        emit(0, "writeint", 0)
        getoken()
        
    #    string
    if token.token == stringsym:
        printMsg()
        getoken()
    
#===============================================================================
def printMsg():
#    <printMsg> ::= printMsg <expression>
#===============================================================================
    emit(0, "loadv", counterafter1)
    emit(0, "store", 1)
    emit(0, "call", 400)
    emit(400, "load-Ind", 0)
    emit(401, "jumpeq", 405)
    emit(402, "writech", 0)
    emit(403, "increment", 1)
    emit(404, "jump", 400)
    emit(405, "return", '')
    

#===============================================================================
def readStmt():
#    <readStmt> ::= read "("variable")"
#===============================================================================

    global idaddress
    
    getoken()
    
    if token.token == leftbracket:
        getoken()
    else:
        error("Expected leftbracket before the variable")
    
    
    variable()
    emit(0, "readint", idaddress)
    
    if token.token == rightbracket:
        getoken()
    else:
        error("Expected rightbracket after the variable")

#===============================================================================
def assignStmt():
#===============================================================================
    """
        <id> = <expression>
    """
    global tokennum
    global whichidentifier
    global whichidaddress
    global arraySubaddress
    
    whichidentifier = token.name  # Remember which ID on Left
    tempadd = token.address
    
    if arraySubaddress != 0:
        whichidaddress = token.address;
    else:
        whichidaddress = arraySubaddress;
    
    getoken()  # Get token after identifier
    
    if token.token == assignsym:
        getoken()

    else:
        error("Expected = in assignment statement")    
    
    expression()
     
    passtoken = token.value
    emit(0, "store", tempadd)

    getoken()
    
    
    
#===============================================================================   
def ifStmt():
# <ifStmt> ::= if (condition) statement [else statement]
#===============================================================================

    getoken()  # skip "if"  
    
    if token.token == leftbracket:
        getoken()
    else:
        error("Expected leftbracket at the start of if-condition")
    
    condition()
    
    if token.token == rightbracket:
        getoken()
    else:
        error("Expected rightbracket at the end of if-condition")
    
    if token.token == leftbrace:
        getoken()
    else:
        error("Expected leftbrace at the start of if-statement")
        
    stmtList()
    getoken()
    
    if token.token == rightbrace:
        getoken()
       
    if token.token == elsesym:
        getoken()
    
        if token.token == leftbrace:
            getoken()
        else:
            error("Expected leftbrace at the start of else-statement")
        
        stmt()
        getoken()
    
        if token.token == rightbrace:
            getoken()
        else:
            error("Expected rightbrace at the end of else-statement")

       
#===============================================================================
def whileStmt():
#    <whileStmt> ::= while (condition)statement
#===============================================================================
    
    getoken()  # skip "while" 
    
    if token.token == leftbracket:
        getoken()
    else:
        error("Expected leftbracket at the start of while-condition")
    
    condition()
    
    if token.token == rightbracket:
        getoken()
    else:
        error("Expected rightbracket at the end of while-condition")
        
    if token.token == leftbrace:
        getoken()
    else:
        error("Expected leftbrace at the start of while-statement")
    
    stmtList()
#    emit(0,"jump",127)
    
    if token.token == rightbrace:
        getoken()
    else:
        error("Expected rightbrace at the end of while-statement")
    

#===============================================================================
def doStmt():
#    doStmt    ::=    <do> stmtList <forever>
#===============================================================================
    getoken()
    stmtList()

#===============================================================================
def returnStmt():
#===============================================================================

    getoken()
    if token.token == leftbracket:
        getoken()
 
    if token.token == idsym:
        expression() 
        emit(0, "jump", 0) 
         
    if token.token == rightbracket:
        getoken()
    else:
        error("Expected rightbracket for return-statement")

#===============================================================================
def condition():
# condition    ::=    [not] conditional-expression
#===============================================================================
    notsign = False;
        
    if token.token == notsym:
        notsign = True;
        getoken()
    
    if notsign == True:
        emit(0, "Not", '')
        conditionalexp()

    else:
        conditionalexp()

#===============================================================================
def conditionalexp():
#    <conditionalexp>    ::=    <expression>[relational_op    <expression>]
#===============================================================================   
    expression()
    
    relational_op()
    
#===============================================================================
def relational_op():
#    <relational_op>    ::=    <|<=|==|!=|>|>=
#===============================================================================  
    
     if token.token == lessthan or token.token == greaterthan or token.token == lessthanequal or token.token == greaterthanequal or token.token == jumpne or token.token == jumpeq:
        op = token  # remember -
        getoken()  # skip past -
        emit(0, "store", 686)  # Save current expression result
        expression()
            
        if op.token == lessthan:
            emit(0, "store", 5)
            emit(0, "load", 686)
            emit(0, "compare", 5)
            emit(0, "jumplt", 137)
            emit(0, "jump", 158)
            
        elif op.token == greaterthan:
            emit(0, "store", 5)
            emit(0, "load", 686)
            emit(0, "compare", 5)
            emit(0, "jumpgt", 158)
            emit(0, "jump", 137)

        elif op.token == lessthanequal:
            emit(0, "store", 5)
            emit(0, "load", 686)
            emit(0, "compare", 5)
            emit(0, "jumplt", 145)
            emit(0, "jumpeq", 145)
            emit(0, "jump", 159)
            
        elif op.token == greaterthanequal:
            emit(0, "store", 5)
            emit(0, "load", 686)
            emit(0, "compare", 5)
            emit(0, "jumpgt", 145)
            emit(0, "jumpeq", 145)
            emit(0, "jump", 159)

        elif op.token == jumpne:
            emit(0, "store", 5)
            emit(0, "load", 686)
            emit(0, "compare", 5)
            emit(0, "jumpne", 128)
            emit(0, "jump", 125)

        elif op.token == jumpeq:
            emit(0, "store", 5)
            emit(0, "load", 686)
            emit(0, "compare", 5)
            emit(0, "jumpeq", 125)
            emit(0, "jump", 128)

#===============================================================================
def expression():
#    <expression> ::=  <term> {  (+ | -)  <term> }
#===============================================================================
    """
       Leaves result in ACC at runtime
       Use addresses 687 as Temporary variables
    """
    global whichidentifier
    global idaddress
    global idvalue     
    
    if whichidentifier == None:
        getoken()
    else:
        idaddress = symtbl[whichidentifier].address 
        idvalue = symtbl[whichidentifier].value 

    if token.token == leftbracket: 
        getoken()           
    
    term()
        
    while token.token == plus or token.token == minus:
        op = token  # remember -
        getoken()  # skip past -
        emit(0, "store", 687)  # Save current result
        term()
        
        
        if op.token == plus:
            emit(0, "add", 687)
        
        elif op.token == minus:  # Subtract - have to swap operand order
            emit(0, "store", 5)
            emit(0, "load", 687)
            emit(0, "subtract", 5)
   
        

#===============================================================================
def term():
#    <term>    ::=    <factor> {(*|/) <factor>}
#===============================================================================
    """ 
        Use addresses 688 as Temporary variables
    """    
    factor()
    
    while token.token == mpy or token.token == div:
        op = token  # remember -
        getoken()  # skip past -
        emit(0, "store", 688)  # Save term result
#        save here xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
        factor()
        
        if op.token == mpy:
            emit(0, "mpy", 688)

        elif op.token == div:
            emit(0, "store", 5)
            emit(0, "load", 688)
            emit(0, "div", 5)

#===============================================================================
def factor():
#    <factor> ::= [+|-] <id> | <number> | "("<expression>")"
#===============================================================================
    """
      # FACTOR() - leaves result in ACC at runtime
    """
    global tokennum
    global whichidentifier
    global idaddress
    global idvalue     
    
    tokensign = False

    #   [+|-] number       
    if token.token == plus:
        getoken()
                    
    # - (unary)
    elif token.token == minus:
        tokensign = True
        getoken()

    # number
    if token.token == number:
        if tokensign == True:
            emit(0, "loadv", 0 - token.value)
            getoken()
        else:
            emit(0, "loadv", token.value)
            tokennum = token.value
            getoken()
            
     #    id
    elif token.token == idsym:
        emit(0, "load", token.address)
        idaddress = token.address
        tempaddress = token.address
        getoken()
        
        if token.token == leftbracket:
            getoken()
        
            expression()
            if token.token == comma:
                # For two parameters
                emit(0, "store", tempaddress + 1)
                getoken()
                expression()
                
                emit(0, "call", 419)
            
            else:
                # For one parameter
                emit(0, "store", tempaddress + 2)
                emit(0, "call", 410)
        
            if token.token == rightbracket:
                getoken()
            else:
                error("Expected rightbracket after the factor")
    
    # "(" <expression> ")"
    elif token.token == leftbracket:
        emit(0, "store", 689)
        emit(0, "push", 1)
        getoken()
        
        expression()

        if token.token == rightbracket:
            getoken() 
            emit(0, "pop", 1)  
            
    else:
        error("Start Of Factor Expected")
         

#===============================================================================
def function():
#===============================================================================
    global codeptr
    global endaddress
    
    beginaddress = codeptr
    if endaddress < 200:
        codeptr = codeptr + 400
    elif endaddress > 400:
        codeptr = endaddress
    
    getoken()
        
    if token.token == idsym:
        getoken()
    
    if token.token == leftbracket:
        getoken()
        
    if token.token == idsym:
        parameters()        

    else:
        error("Function error : No_parameter_input_for_function")

    if token.token == rightbracket:
        getoken()  
    else:
        error("Expected rightbracket for parameter")
    
    if token.token == semicolon:
        getoken()
    else:
        error("Expected semicolon after parameter")
            
    if token.token == declaresym:
        declareList()

    if token.token == leftbrace:
        getoken()
    
    stmtList() 
        
    if token.token == rightbrace:
        getoken()
        print ("#---Function Finished---")
    
    endaddress = codeptr
        
#===============================================================================
def program():
#    <program>       ::=     program <id>; declare    declareList;    { StmtList}
#===============================================================================
    global codeptr
    
    beginaddress = codeptr
    
    if token.token == leftbrace:
        getoken()

    if token.token == programsym:

        getoken()
    else: error("Program start with 'program' keyword")

    if token.token == idsym:

        getoken()

    if token.token == semicolon:

        getoken()

    if token.token == declaresym :
        declareList()
    
    while token.token == functionsym:
        function()
    
    codeptr = beginaddress        
    if token.token == leftbrace:
        getoken()

    stmtList()
    
    if token.token == rightbrace:
        print "#***Compilation Finished****"

#======================================================================
def main():
#======================================================================
    global line
    global srcfile
    global charIndex

    initSymTbl()

    with open("test2.txt") as srcfile:

        line = srcfile.read()

    charIndex = 0

    debugScanner = False
    if debugScanner:  # Scanner Test Routine - Read a line and display the tokens
       getoken()
       while token.token is not None:  # Skeleton for testing Scanner
           printToken(token)
           getoken()
       sys.exit(1)
    else:
        getoken()  # Parse Program according to the grammar
        program()


#===============================================================================
# Main Compiler starts here
#===============================================================================

print "#Microcompiler.py"
main()

"""
srcfile = open('test.txt', 'r')
lexer = shlex.shlex(srcfile)
for token in lexer:
    print repr(token)
"""


